import logging
from functools import wraps
from typing import Callable, TypeVar, cast

from flask import Blueprint, current_app, request
from flask import jsonify

from airflow.patsnap.service import datasource_service
from airflow.exceptions import AirflowException
from airflow.models.idata_datasource import Datasource
from airflow.www.api import provide_user

log = logging.getLogger(__name__)

T = TypeVar("T", bound=Callable)  # pylint: disable=invalid-name


def requires_authentication(function: T):
    """Decorator for functions that require authentication"""

    @wraps(function)
    def decorated(*args, **kwargs):
        return current_app.api_auth.requires_authentication(function)(*args, **kwargs)

    return cast(T, decorated)


api_speech_datasource = Blueprint('api_speech_datasource', __name__)


# user route
@api_speech_datasource.route('/datasources/<int:id>', methods=['GET'])
def get_datasource(id):
    try:
        datasource = Datasource.get_datasource(id)
        return jsonify(code=0, message='ok', data=datasource.to_json())
    except AirflowException as e:
        log.error("get_datasource error =%s, params=%s", e, id, )
        return jsonify(code=500, message=str(e), data=None)


@api_speech_datasource.route('/datasources', methods=['GET'])
def get_datasources():
    try:
        page = request.args.get('page', 0, type=int)
        project_id = request.values.get("project_id", type=str, default=None)
        datasource_type = request.values.get("type", type=int, default=None)
        result = datasource_service.get_datasources(page, project_id, datasource_type)
        return jsonify(code=0, message='ok', data=result)
    except AirflowException as e:
        log.error("get_datasources error =%s", e, )
        return jsonify(code=500, message=str(e), data=None)


@api_speech_datasource.route('/datasources', methods=['POST'])
@provide_user
def add_datasource(oa_user_name):
    try:
        datasource_type = request.values.get("type", type=int, default=None)
        name = request.values.get("name", type=str, default=None)
        ip = request.values.get("ip", type=str, default='')
        port = request.values.get("port", type=int, default=0)
        user_name = request.values.get("userName", type=str, default='')
        password = request.values.get("password", type=str, default='')
        project_ids = request.json

        if datasource_type is None or name is None or project_ids is None:
            log.error(
                "add_datasource params error datasource_type={%s},name={%s},project_ids={%s}",
                datasource_type, name, project_ids)
            return jsonify(code=400, message="add_projects params has None,", data=None)
        datasource_service.add_datasource(datasource_type, name, ip, port, user_name, password, project_ids, oa_user_name)
        return jsonify(code=0, message='ok', data=None)
    except AirflowException as e:
        log.error("add_datasource error =%s", e)
        return jsonify(code=500, message=str(e), data=None)


@api_speech_datasource.route('/datasources/<int:id>', methods=['DELETE'])
def delete_datasource(id):
    try:
        datasource_service.delete_datasource(id)
        return jsonify(code=0, message='ok', data=None)
    except AirflowException as e:
        log.error("delete_datasource error =%s", e)
        return jsonify(code=500, message=str(e), data=None)


@api_speech_datasource.route('/datasources', methods=['PUT'])
@provide_user
def update_datasource(oa_user_name):
    try:
        datasource_id = request.values.get("id", type=int, default=None)
        datasource_type = request.values.get("type", type=int, default=None)
        name = request.values.get("name", type=str, default=None)
        ip = request.values.get("ip", type=str, default='')
        port = request.values.get("port", type=int, default=0)
        user_name = request.values.get("userName", type=str, default='')
        password = request.values.get("password", type=str, default='')
        project_ids = request.json

        if datasource_id is None or datasource_type is None or name is None or project_ids is None:
            log.error(
                "update_datasource params error datasource_id={%s},datasource_type={%s},name={%s},project_ids={%s}",
                datasource_id, datasource_type, name, project_ids)
            return jsonify(code=400, message="update_datasource params has None,", data=None)
        datasource_service.update_datasource(datasource_id, datasource_type, name, ip, port, user_name, password, project_ids, oa_user_name)
        return jsonify(code=0, message='ok', data=None)
    except AirflowException as e:
        log.error("update_datasource error =%s", e)
        return jsonify(code=500, message=str(e), data=None)
